﻿using System;
using Outlook = Microsoft.Office.Interop.Outlook;
using Core = Microsoft.Office.Core;
using Folder = OMC.DataManagement.Folder;
using MenuItem = OMC.DataManagement.MenuItem;
using Manager = OMC.DataManagement.Manager;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Resources;
using System.Threading;

namespace OMC.AddInHandling
{
    /// <summary>
    /// an object of this class could manage all the things
    /// which are responsable of outlook actions
    /// </summary>
    /// <remarks>
    /// Copyright 2012 Stefan Lütolf
    /// </remarks>
    class AddInHandler
    {
        private Outlook.Explorer TheExplorer;
        private Outlook.Accounts TheAccounts;
        private Manager TheManager { get; set; }
        private Folder TheFolder { get; set; }
        private String TheTextOfTheContextPopupMenu;
        private String TheTextOfContextMenuRefreshButton;
        private String TheTextofMailNotMoved;
        private String TheTextOfContextMenuSaveButton;
        private String TheTextOfSaveFileDialogFilter;
        private String TheTextOfSaveFileDialogTitle;
        private List<String> TheDefaultFolderNameList;
        private Core.CommandBarPopup ThePopUpMenu;
        private Core.CommandBarButton TheButton;

        /// <summary>
        /// constructor to create an object of this class
        /// </summary>
        /// <param name="inExplorer">Outlook.Explorer type of the actual application</param>
        /// <param name="inAccounts">Outlook.Accounts of the actual application</param>
        /// <param name="inManager">a manager object of class DataManagement.Manager</param>
        public AddInHandler(Outlook.Explorer inExplorer, Outlook.Accounts inAccounts, DataManagement.Manager inManager)
        {
            this.TheExplorer = inExplorer;
            this.TheAccounts = inAccounts;
            this.TheManager = inManager;
            this.init();
        }

        /// <summary>
        /// to init standard resources and default folders
        /// </summary>
        private void init()
        {
            this.createDefaultFolderList();
            this.loadResources();

        }

        /// <summary>
        /// to load the string resources of the text, which is shown in the user interface.
        /// there are language files based on the culture info. default is "en"!
        /// </summary>
        /// <example>
        /// cultureinfo convention
        /// Source:http://msdn.microsoft.com/de-de/library/system.globalization.cultureinfo%28v=vs.80%29.aspx
        /// </example>
        private void loadResources()
        {
            ResourceManager rm = BA.Properties.StringResources.ResourceManager;

            TheTextOfTheContextPopupMenu = rm.GetString("ContextMenuPopupName");
            TheTextOfContextMenuRefreshButton = rm.GetString("ContextMenuRefresh");
            TheTextofMailNotMoved = rm.GetString("MailNotMoved");
            TheTextOfContextMenuSaveButton = rm.GetString("ContextMenuSave");
            TheTextOfSaveFileDialogFilter = rm.GetString("saveFileDialogFilter");
            TheTextOfSaveFileDialogTitle = rm.GetString("saveFileDialogTitle");
        }

        /// <summary>
        /// creates a list of string items, which represent the default folders in outlook to exclude them
        /// in the calculation of the classification
        /// </summary>
        private void createDefaultFolderList()
        {
            TheDefaultFolderNameList = new List<String>();
            Outlook.NameSpace TheNameSpace = TheExplorer.Application.GetNamespace("MAPI");

            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderConflicts).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDrafts).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderJournal).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderJunk).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderLocalFailures).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderManagedEmail).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderNotes).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderOutbox).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderRssFeeds).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderServerFailures).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSuggestedContacts).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSyncIssues).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderTasks).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderToDo).Name); }
            catch { }
            try { TheDefaultFolderNameList.Add(TheNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olPublicFoldersAllPublicFolders).Name); }
            catch { }
        }

        /// <summary>
        /// to load the mail data of all accounts into the referenced list
        /// which contain folders which contain mailcontents. The loaded maildata
        /// are "mirrored" in the list of folder items
        /// </summary>
        /// <param name="inList">a referenced list of Folder items</param>
        public void loadMailData(ref List<Folder> inList)
        {
            //Go threw Accounts
            foreach (Outlook.Account TheAccount in TheAccounts)
            {
                //Get Mailfolders and Enumerate them recursive
                Outlook.Folder TheRootFolder = TheAccount.DeliveryStore.GetRootFolder() as Outlook.Folder;
                createMailData(TheAccount, TheRootFolder, ref inList);
            }
        }

        /// <summary>
        /// a recursiv method, to create MailContents of the MailItems of
        /// all accounts. A few default folders are ignored, such as
        /// inbox, outbox, deleted items..
        /// </summary>
        /// <param name="inAccount">the actual account</param>
        /// <param name="inRootFolder">the actual rootFolder</param>
        /// <param name="inList">the referenced list of folder items</param>
        private void createMailData(Outlook.Account inAccount, Outlook.Folder inRootFolder, ref List<Folder> inList)
        {
            Outlook.Folders TheChildFolders = inRootFolder.Folders;
            if (TheChildFolders.Count > 0)
            {
                foreach (Outlook.Folder TheChildFolder in TheChildFolders)
                {
                    if (chekFolder(TheChildFolder))
                    {
                        //Check, if childFolder contains any elements
                        if (TheChildFolder.Items.Count > 0)
                        {
                            TheFolder = new Folder(TheChildFolder.Name, inAccount.DisplayName);
                            foreach (Outlook.MailItem item in TheChildFolder.Items)
                            {
                                TheFolder.addMailContent(item.Body, item.Subject, item.SenderEmailAddress, item.To);
                            }
                            inList.Add(TheFolder);
                        }
                    }
                    createMailData(inAccount, TheChildFolder, ref inList);
                }
            }
        }

        /// <summary>
        /// to check the folder default item type and if the folder is type of default folders
        /// </summary>
        /// <param name="inFolder">in folder to check</param>
        /// <returns>
        /// true, if folder could be used
        /// false, if folder schould be banned
        /// </returns>
        private bool chekFolder(Outlook.Folder inFolder)
        {
            if (inFolder.DefaultItemType == Outlook.OlItemType.olMailItem)
            {
                foreach (String DefaultFolderName in TheDefaultFolderNameList)
                {
                    if (inFolder.Name.Equals(DefaultFolderName))
                    {
                        return false;
                    }
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// to move mails from a folder to another folder
        /// </summary>
        /// <param name="inMailItem">the MailItem, which should be moved</param>
        /// <param name="inFolderName">the destination folder of the MailItem</param>
        public void moveMail(ref Outlook.MailItem inMailItem, ref String inFolderName)
        {
            foreach (Outlook.Account account in TheAccounts)
            {
                Outlook.Folder root = account.DeliveryStore.GetRootFolder() as Outlook.Folder;
                searchFolderToMoveMail(root, ref inFolderName, ref inMailItem);
            }
        }

        /// <summary>
        /// to search the folder in the root node and move the mail item to them
        /// </summary>
        /// <param name="inFolder">folder, which could contain the possible searched folder</param>
        /// <param name="inFolderName">the name of the searched folder</param>
        /// <param name="inMailItem">the mail item to move</param>
        public void searchFolderToMoveMail(Outlook.Folder inFolder, ref String inFolderName, ref Outlook.MailItem inMailItem)
        {
            foreach (Outlook.Folder TheFolder in inFolder.Folders)
            {
                if (TheFolder.Name == inFolderName)
                {
                    try
                    {
                        inMailItem.Move(TheFolder);
                    }
                    catch
                    {
                        MessageBox.Show("Mail wurde nicht verschoben");
                    }
                }
                searchFolderToMoveMail(TheFolder, ref inFolderName, ref inMailItem);
            }

        }

        /// <summary>
        /// creates a contextmenu item, which is type of popup menu
        /// </summary>
        /// <param name="inCommandBar">the command bar of the right clicked item</param>
        public void creatContextMenuPopup(Core.CommandBar inCommandBar)
        {
            //Create PopUpMenu in the ContextMenu
            ThePopUpMenu = inCommandBar.Controls.Add(Core.MsoControlType.msoControlPopup,
                                                     Type.Missing,
                                                     Type.Missing,
                                                     Type.Missing, true) as Core.CommandBarPopup;
            ThePopUpMenu.BeginGroup = true;
            ThePopUpMenu.Caption = TheTextOfTheContextPopupMenu;
            ThePopUpMenu.Enabled = false;

            //set PopUpMenu Visible
            ThePopUpMenu.Visible = true;
        }

        /// <summary>
        /// this Methode could be use to create the Context menu of
        /// each Mailitem with the assoziated Folder, classified by Weka
        /// </summary>
        /// <example>
        /// Source CommandBar:  http://support.microsoft.com/kb/303018
        /// Source FaceID:      http://www.kebabshopblues.co.uk/2007/01/04/visual-studio-2005-tools-for-office-commandbarbutton-faceid-property/
        /// </example>
        /// <param name="inCommandBar">this Commandbar could be modified</param>
        /// <param name="inList">a list, which contains the classified folder names of the selected mail item</param>
        /// <param name="inMailItem">the selected mail item</param>
        public void createContextMenuContent(Core.CommandBar inCommandBar, ref List<MenuItem> inList, Outlook.MailItem inMailItem)
        {
            inList.Reverse();
            foreach (MenuItem TheMenuItem in inList)
            {
                //Create Buttons to the PopUpMenu
                TheButton = ThePopUpMenu.Controls.Add(Core.MsoControlType.msoControlButton,
                                                    Type.Missing,
                                                    Type.Missing,
                                                    Type.Missing, true) as Core.CommandBarButton;
                TheButton.Style = Core.MsoButtonStyle.msoButtonIconAndWrapCaption;
                TheButton.FaceId = 0133;
                TheButton.Caption = TheMenuItem.FolderName + "  (" + TheMenuItem.probability + " %)";

                //Set delegate to the ClickEventHandler
                String TheFolderName = TheMenuItem.FolderName;
                TheButton.Click += new Core._CommandBarButtonEvents_ClickEventHandler(
                        (Core.CommandBarButton Cmd, ref bool Can) => TheButton_Click(Cmd, ref Can, ref inMailItem, ref TheFolderName));
                TheButton.Visible = true;
            }

            //Create Refresh Buttons to the PopUpMenu
            TheButton = ThePopUpMenu.Controls.Add(Core.MsoControlType.msoControlButton,
                                                Type.Missing,
                                                Type.Missing,
                                                Type.Missing, true) as Core.CommandBarButton;
            TheButton.BeginGroup = true;
            TheButton.Style = Core.MsoButtonStyle.msoButtonIconAndWrapCaption;
            TheButton.FaceId = 0037;
            TheButton.Caption = TheTextOfContextMenuRefreshButton;

            //Set delegate to the ClickEventHandler
            TheButton.Click += new Core._CommandBarButtonEvents_ClickEventHandler(TheRefreshButton_Click);
            TheButton.Visible = true;

            //Create Save to ARFF Buttons to the PopUpMenu
            TheButton = ThePopUpMenu.Controls.Add(Core.MsoControlType.msoControlButton,
                                                Type.Missing,
                                                Type.Missing,
                                                Type.Missing, true) as Core.CommandBarButton;
            TheButton.Style = Core.MsoButtonStyle.msoButtonIconAndWrapCaption;
            TheButton.FaceId = 0003;
            TheButton.Caption = TheTextOfContextMenuSaveButton;

            //Set delegate to the ClickEventHandler
            TheButton.Click += new Core._CommandBarButtonEvents_ClickEventHandler(TheSaveButton_Click);
            TheButton.Visible = true;

            //Set PopUpMenu enabled
            ThePopUpMenu.Enabled = true;
        }

        /// <summary>
        /// the method, which is called by a button events handler
        /// </summary>
        /// <param name="inCommandBarButton">the commandbar button, which called this method</param>
        /// <param name="Cancel">cancel</param>
        /// <param name="inMailItem">the mail item to move</param>
        /// <param name="inClassifiedFolderName">the folder name of the destination folder of the mail item</param>
        private void TheButton_Click(Core.CommandBarButton inCommandBarButton, ref bool Cancel,
                                     ref Outlook.MailItem inMailItem, ref String inClassifiedFolderName)
        {
            moveMail(ref inMailItem, ref inClassifiedFolderName);
        }

        /// <summary>
        /// the method, which is called by the button handler of the refresh button.
        /// this could be used, to refresh manually the dataset
        /// </summary>
        /// <param name="inCommandBarButton">the commandbar button, which called this method</param>
        /// <param name="Cancel">cancel</param>
        private void TheRefreshButton_Click(Core.CommandBarButton inCommandBarButton, ref bool Cancel)
        {
            ThePopUpMenu.Enabled = false;
            TheManager.load();
            ThePopUpMenu.Enabled = true;
        }

        /// <summary>
        /// the method, which is called by the button handler of the save button.
        /// this could be used, to save the data to a arff file
        /// </summary>
        /// <param name="inCommandBarButton">the commandbar button, which called this method</param>
        /// <param name="Cancel">cancel</param>
        private void TheSaveButton_Click(Core.CommandBarButton inCommandBarButton, ref bool Cancel)
        {
            ThePopUpMenu.Enabled = false;

            // Displays a SaveFileDialog so the user can save the Image
            // assigned to Button2.
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = TheTextOfSaveFileDialogFilter;
            saveFileDialog.Title = TheTextOfSaveFileDialogTitle;
            saveFileDialog.ShowDialog();

            // If the file name is not an empty string open it for saving.
            if (saveFileDialog.FileName != "")
            {
                String TheFilePath = saveFileDialog.InitialDirectory + saveFileDialog.FileName;
                switch (saveFileDialog.FilterIndex)
                {
                    case 1: //default Weka arff file
                        TheManager.saveToFile(ref TheFilePath, false);
                        break;
                    case 2: //filtered Weka arff file
                        TheManager.saveToFile(ref TheFilePath, true);
                        break;
                }
            }
            ThePopUpMenu.Enabled = true;
        }
    }
}